package service

import (
	"context"
	"go-mall/conf"
	"go-mall/dao"
	"go-mall/model"
	"go-mall/pkg/e"
	"go-mall/pkg/util"
	"go-mall/serializer"
	"golang.org/x/crypto/bcrypt"
	"gopkg.in/mail.v2"
	"mime/multipart"
	"strings"
	"time"
)

type UserService struct {
	NickName string `json:"nick_name" form:"nick_name"`
	UserName string `json:"user_name" form:"user_name"`
	Password string `json:"password" form:"password"`
	Mobile   string `json:"mobile" form:"mobile"`
	Email    string `json:"email" form:"email"`
	Avatar   string `json:"avatar" form:"avatar"`
	Key      string `json:"key" form:"key"` //现阶段前端验证
}

type SendEmailService struct {
	Email         string `json:"email" form:"email"`
	Password      string `json:"password" form:"password"`
	OperationType uint   `json:"operation_type" form:"operation_type"`
	//1绑定邮箱 2解绑邮箱 3改密码
}

type ValidEmailService struct {
}

type ShowMoneyService struct {
	Key string `json:"key" form:"key"`
}

// 注册
func (service *UserService) Register(ctx context.Context) serializer.Response {
	var user model.User
	code := e.Success

	//手机号是否正确
	if !util.IsValidPhoneNumber(service.Mobile) {
		code = e.ErrorMobileAndEmail
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	//用户已存在
	userDao := dao.NewUserDao(ctx)
	_, exist, _ := userDao.ExistOrNotByUserMobile(service.Mobile)
	if exist {
		code = e.ErrorExistPhone
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	//初始金额的加密
	money, err := util.EncryptMoney("1000")
	if err != nil {
		code = e.ErrorMoney
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	user = model.User{
		Mobile:   service.Mobile,
		NickName: service.Mobile,
		UserName: service.Mobile, //这个用户名应该是用户实名的用户名 现在因为是个人用户所以开通不网上实名api
		Status:   model.Active,
		Avatar:   "http://ryuo42yph.hn-bkt.clouddn.com/avatar/missing-face.png", //默认头像
		Money:    money,
		Uuid:     util.NewUuid(), //用户uuid
	}

	//解密密码
	password, _ := util.DecryptPassword(service.Password)
	//加密密码
	bytePassword, _ := util.GenPwd(password)
	user.PasswordDigest = string(bytePassword)

	//	创建用户
	err = userDao.CreateUser(&user)
	if err != nil {
		code = e.Error
	}
	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
	}
}

// 登录
func (service *UserService) Login(ctx context.Context) serializer.Response {
	//用户结构体
	var user *model.User
	//请求成功的状态码
	code := e.Success

	//手机号是否正常
	if !util.IsValidPhoneNumber(service.Mobile) {
		code = e.ErrorMobileAndEmail
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	userDao := dao.NewUserDao(ctx)

	user, exist, err := userDao.ExistOrNotByUserMobile(service.Mobile)
	//用户未注册
	if !exist {
		code = e.ErrorUserNot
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	//解密密码
	password, _ := util.DecryptPassword(service.Password)
	err = bcrypt.CompareHashAndPassword([]byte(user.PasswordDigest), []byte(password))
	if err != nil {
		code = e.ErrorNotCompare
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}

	//token分发 每次登录需要把token返回给用户
	//http是无状态的 http的每次请求都不知是谁
	//http无状态(认证,token)
	token, err := util.GenerateToken(user.ID, service.UserName, 0)
	if err != nil {
		code = e.ErrorAuthToken
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	return serializer.Response{
		Status: code,
		Data:   serializer.TokenData{User: serializer.BuildUser(user), Token: token},
		Msg:    e.GetMsg(code),
	}
}

func (service *UserService) Info(ctx context.Context, uId uint) serializer.Response {
	code := e.Success
	userDao := dao.NewUserDao(ctx)
	user, err := userDao.GetUserById(uId)
	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
		Data:   serializer.BuildUser(user),
	}
}

// 更改用户信息
func (service *UserService) Update(ctx context.Context, uId uint) serializer.Response {

	var user *model.User
	var err error
	code := e.Success

	//	找到这个用户
	userDao := dao.NewUserDao(ctx)
	user, err = userDao.GetUserById(uId)

	//参数是否为空
	if service.NickName == "" || service.Mobile == "" || service.Avatar == "" || service.Email == "" {
		code = e.ParamsNOt
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	//手机号和邮箱是否正确
	if !util.IsValidPhoneNumber(service.Mobile) || !util.IsValidEmail(service.Email) {
		code = e.ErrorMobileAndEmail
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	//是否有空格等特殊字符
	if util.ContainsSpaceAndSpecialChars(service.NickName) {
		code = e.ErrorString
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	user.NickName = service.NickName
	user.Mobile = service.Mobile
	user.Avatar = service.Avatar
	user.Email = service.Email

	err = userDao.UpdateUserById(uId, user)
	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
		Data:   serializer.BuildUser(user),
	}
}

// post更新头像
func (service *UserService) Post(ctx context.Context, uId uint, file multipart.File, fileSize int64) serializer.Response {
	code := e.Success
	var user *model.User
	var err error
	userDao := dao.NewUserDao(ctx)
	user, err = userDao.GetUserById(uId)
	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	//	保存图片到本地函数
	path, err := UploadAvatarTOLocalStatic(file, uId, user.UserName)
	if err != nil {
		code = e.ErrorUploadFail
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	user.Avatar = path
	err = userDao.UpdateUserById(uId, user)
	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
		Data:   serializer.BuildUser(user),
	}
}

// 发送邮箱
func (service *SendEmailService) Send(ctx context.Context, uId uint) serializer.Response {
	code := e.Success
	var address string       //发送地址
	var notice *model.Notice //绑定邮箱 修改密码，模板通知
	token, err := util.GenerateEmailToken(uId, service.OperationType, service.Email, service.Password)
	if err != nil {
		code = e.ErrorAuthToken
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	noticeDao := dao.NewNoticeDao(ctx)
	notice, err = noticeDao.GetNoticeById(service.OperationType)
	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	address = conf.ValidEmail + token //发送方
	mailStr := notice.Text
	mailText := strings.Replace(mailStr, "Email", address, -1)
	m := mail.NewMessage()
	m.SetHeader("From", conf.SmtEmail)
	m.SetHeader("To", service.Email)
	m.SetHeader("Subject", "FanOne")
	m.SetBody("text/html", mailText)
	d := mail.NewDialer(conf.SmtpHost, 465, conf.SmtEmail, conf.SmtPass)
	d.StartTLSPolicy = mail.MandatoryStartTLS
	if err = d.DialAndSend(m); err != nil {
		code = e.ErrorSendMail
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
			Error:  err.Error(),
		}
	}
	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
	}
}

// 验证邮箱
func (service *ValidEmailService) Valid(ctx context.Context, token string) serializer.Response {
	var userId uint
	var email string
	var password string
	var operationType uint
	code := e.Success
	//	验证token
	if token == "" {
		code = e.InvalidParams
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	} else {
		claims, err := util.ParseEmailToken(token)
		if err != nil {
			code = e.ErrorAuthToken
		} else if time.Now().Unix() > claims.ExpiresAt {
			code = e.ErrorAuthCheckTokenTimeout
		} else {
			userId = claims.UserID
			email = claims.Email
			password = claims.Password
			operationType = claims.OperationType
		}
	}
	if code != e.Success {
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	//	获取该用户的信息
	userDao := dao.NewUserDao(ctx)
	user, err := userDao.GetUserById(userId)
	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	if operationType == 1 {
		//	绑定邮箱
		user.Email = email
	} else if operationType == 2 {
		//	解绑邮箱
		user.Email = ""
	} else {
		err = user.SetPassword(password)
		if err != nil {
			code = e.Error
			return serializer.Response{
				Status: code,
				Msg:    e.GetMsg(code),
			}
		}
	}
	err = userDao.UpdateUserById(userId, user)
	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
		Data:   serializer.BuildUser(user),
	}
}

func (service *ShowMoneyService) Show(ctx context.Context, uId uint) serializer.Response {
	code := e.Success
	userDao := dao.NewUserDao(ctx)
	user, err := userDao.GetUserById(uId)

	if err != nil {
		code = e.Error
		return serializer.Response{
			Status: code,
			Msg:    e.GetMsg(code),
		}
	}
	return serializer.Response{
		Status: code,
		Msg:    e.GetMsg(code),
		Data:   serializer.BuildMoney(user),
	}
}
